# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.exceptions import StopConsumer
from random import randint
from . import utils

utils.EXPIRATION_TIME = 60 * 60 * 1
FIRST_RUN = True

def get_user_list_by_room_group_name(room_group_name):
    ret = utils.room_id_to_user_list.show_user_list(room_group_name)
    return ret


def add_username_to_room_user_list(room_group_name, client_name):
    ret = utils.room_id_to_user_list.add_user_to_user_list(room_group_name, client_name)
    return ret


def remove_user_from_user_list_by_name(room_group_name, client_name):
    ret = utils.room_id_to_user_list.remove_user_from_user_list(room_group_name, client_name)

    return ret


def get_user_channel(room_group_name, client_name):
    # 踢人的时候要用, 根据房间&用户id, 找到他对应的channel, 然后用discord踢出房间
    ret = utils.user_id_compare_channel.remove_channel(room_group_name, client_name)
    return ret


class ChatConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name
        self.client_url = ':'.join([str(i) for i in self.scope['client']])

        self.user_id = randint(1000, 9999)
        self.client_name = self.get_client_name_by_id(self.user_id)
        self.role = 'user'

        global  FIRST_RUN
        if FIRST_RUN:
            # 初次运行时, 置空本项目要用的keyname.
            utils.init_redis_by_room_group_name(self.room_group_name)
            FIRST_RUN = not FIRST_RUN

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

        message = f'{self.client_name} 加入了房间'

        add_username_to_room_user_list(self.room_group_name, self.client_name)
        user_list = get_user_list_by_room_group_name(self.room_group_name)

        # 必须根据id获取
        utils.user_id_compare_channel.save_room_user_channel(self.room_group_name, self.user_id, self.channel_name, ex=60*60*3)
        utils.user_id_compare_channel.show_all(self.room_group_name)

        dc = {
            'message': message,
            'user_list': user_list,
        }
        await self.send_dict_data(dc)

    @staticmethod
    def get_client_name_by_id(user_id):
        ret = f'用户[{user_id}]'
        return ret

    async def kick_user_by_id(self, room_group_name, user_id):
        print(f'====== 正在踢出[{room_group_name}]房间的[{user_id}]用户...')

        utils.user_id_compare_channel.show_all(room_group_name)

        # 踢人的时候要用, 根据房间&用户id, 找到他对应的channel, 然后用discord踢出房间
        channel_name = utils.user_id_compare_channel.get_user_channel_by_user_id(room_group_name, user_id)

        print(self.groups)
        # self.groups
        await self.channel_layer.group_discard(
            room_group_name,
            channel_name
        )

        # from asgiref.sync import async_to_sync
        # async_to_sync(self.channel_layer.group_discard)(room_group_name, channel_name)

        print("--- 成功踢出. ---")

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
        message = f'{self.client_name} 离开了房间'
        print(f'---- 当前{self.room_group_name} : {get_user_list_by_room_group_name(self.room_group_name)} -- {message} ------')

        remove_user_from_user_list_by_name(self.room_group_name, self.client_name)

        user_list = get_user_list_by_room_group_name(self.room_group_name)

        dc = {
            'message': message,
            'user_list': user_list,
        }
        await self.send_dict_data(dc)

    # Receive message from WebSocket
    async def receive(self, text_data=None, bytes_data=None):
        print('~~~~~ mydata: ', text_data, ' --- ', bytes_data, '~~~~~~`')
        if text_data is None:
            # Unity的C-Sharp-Client
            print('--------- 收到的是bytes_data!', bytes_data)
            text_data_json = json.loads(bytes_data)
            message = text_data_json['message']
        else:
            text_data_json = json.loads(text_data)
            message: str = text_data_json['message']['user_input']

        print("--- 本条信息来自: ", self.client_name, ' ~~~~ 内容为: ', text_data_json, '~~~~~~~~~~~~~')

        # xx: str = text_data_json['message']['test']
        # xx

        if utils.is_black(self.room_group_name, self.client_name):
            message = f'------ 您已经被关小黑屋了! --- message: {message} ---'
            print(message)
            return 0

        if message == 'superuser':
            message = f"系统信息: --- {self.client_name}升级为超级管理员! "
            self.role = 'superuser'
            self.client_name = f'超级管理员[{self.user_id}]'
            await self.send_chat_message(message)
            return 1

        if self.role == 'superuser' and message.startswith('踢出用户'):
        # if message.startswith('_'):
            i0, i1 = message.find('['), message.find(']')
            if i0 != -1 and i1 != -1:
                kicked_user_id = message[i0+1:i1]
                kicked_user_name = self.get_client_name_by_id(kicked_user_id)
                utils.add_someone_to_blacklist(self.room_group_name, kicked_user_name, ex=60*30*3)   # 加入黑名单, 伪踢出

                message = f'----- 用户[{kicked_user_id}]被踢出了房间 --------'

                # 从redis中删除该房间中被踢出的用户
                utils.room_id_to_user_list.remove_user_from_user_list(self.room_group_name, kicked_user_name)

                user_list = get_user_list_by_room_group_name(self.room_group_name)
                dc = {
                    'message': message,
                    'user_list': user_list,
                }
                await self.send_dict_data(dc)

                await self.kick_user_by_id(self.room_group_name, kicked_user_id)      # 要先发消息给被踢的人, 再踢了他.

                return 1

        message = f'{self.client_name}: {message}'
        await self.send_chat_message(message)

    # Receive message from room group
    async def chat_message(self, event):
        message = event['message']
        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': message
        }))

    async def room_user_list(self, event):
        user_list = event['message']

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': '',
            'user_list': user_list
        }))

    async def send_room_user_list(self, user_list: list):
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'room_user_list',
                'message': user_list
            }
        )

    # 给聊天室发送message
    async def send_chat_message(self, message: str):
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # 给聊天室发送当前在线的用户列表
    async def send_user_list(self, user_list: list):
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'user_list',
                'message': user_list
            }
        )

    async def dict_data(self, event):
        dc = event['dc']
        await self.send(text_data=json.dumps(dc))

    async def send_dict_data(self, dc: dict):

        # await self.send(text_data=json.dumps(dc))
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'dict_data',
                'dc': dc,
            }
        )


if __name__ == '__main__':
    from channels.layers import get_channel_layer

    channel_layer = get_channel_layer()



    # await channel_layer.send("channel_name", {
    #     "type": "chat.message",
    #     "text": "Hello there!",
    # })
